package com.atguigu.tingshu.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.factory.GuiguItemType;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.lettuce.core.models.stream.ClaimedMessages;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaSigner;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.security.interfaces.RSAPrivateKey;
import java.util.ArrayList;
import java.util.List;

/**
 * 会员订单的实现类
 */
@Slf4j
@Service("vipOrderInfoServiceImpl")
@SuppressWarnings({"unchecked", "rawtypes"})
@GuiguItemType(itemType = SystemConstant.ORDER_ITEM_TYPE_VIP)
@Transactional(rollbackFor = Exception.class)
public class VipOrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Resource
    private OrderInfoMapper orderInfoMapper;

    @Resource
    private OrderDetailMapper orderDetailMapper;

    @Resource
    private OrderDerateMapper orderDerateMapper;

    @Resource
    private UserInfoFeignClient userInfoFeignClient;

    @Resource
    public RSAPrivateKey rsaPrivateKey;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    // @Override
    // public String getItemType() {
    //     return SystemConstant.ORDER_ITEM_TYPE_VIP;
    // }

    /**
     * 订单确认接口
     * @param tradeVo
     * @return
     */
    @Override
    public Object trade(TradeVo tradeVo) {
        // 获取用户购买的VIP服务的id
        Long itemId = tradeVo.getItemId();
        // System.out.println("购买会员触发");
        VipServiceConfig vipServiceConfig
                = userInfoFeignClient.getVipServiceConfig(itemId);
        //包装订单对象: 不写入数据库
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        //交易号
        orderInfoVo.setTradeNo(IdWorker.get32UUID());
        //支付方式: 默认为微信
        orderInfoVo.setPayWay("1101");
        //购买的类型
        orderInfoVo.setItemType(SystemConstant.ORDER_ITEM_TYPE_VIP);
        //原始金额
        orderInfoVo.setOriginalAmount(vipServiceConfig.getPrice());
        //订单金额
        orderInfoVo.setOrderAmount(vipServiceConfig.getDiscountPrice());
        //减免金额 = 原价 - 订单实际价格
        orderInfoVo.setDerateAmount(
                orderInfoVo.getOriginalAmount()
                           .subtract(orderInfoVo.getOrderAmount())
        );

        // 声明订单的详情对象
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        OrderDetailVo orderDetailVo = new OrderDetailVo();
        orderDetailVo.setItemId(itemId);
        orderDetailVo.setItemName(vipServiceConfig.getName());
        orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
        orderDetailVo.setItemPrice(vipServiceConfig.getDiscountPrice());

        orderDetailVoList.add(orderDetailVo); // vip服务一次只能购买一种
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);

        // 声明订单的减免详细
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();
        OrderDerateVo orderDerateVo = new OrderDerateVo();
        orderDerateVo.setDerateType("1406");
        orderDerateVo.setDerateAmount(orderInfoVo.getDerateAmount());
        orderDerateVo.setRemarks("vip会员折扣!!");

        orderDerateVoList.add(orderDerateVo);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);
        //时间戳
        orderInfoVo.setTimestamp(System.currentTimeMillis());
        //签名-JWT 将订单信息使用私钥签名 确保不会被篡改
        Jwt encode =
                JwtHelper.encode(JSONObject.toJSONString(orderInfoVo), new RsaSigner(rsaPrivateKey));
        orderInfoVo.setSign(encode.getEncoded());
        //返回订单对象
        return orderInfoVo;
    }

    /**
     * 提交订单: 写入数据库
     * @param orderInfoVo
     * @return
     */
    @Override
    public Object submitOrder(OrderInfoVo orderInfoVo) {
        // 获取支付方式
        String payWay = orderInfoVo.getPayWay();
        // 用公钥尝试获取签名 成功则获取到载荷中的信息 失败则报异常
        String sign = orderInfoVo.getSign();
        try {
            Jwt jwt = JwtHelper.decodeAndVerify(sign, new RsaVerifier(SystemConstant.PUBLIC_KEY));
            // 获取载荷
            String claims = jwt.getClaims();
            // 反序列化 获得载荷中的信息
            orderInfoVo = JSONObject.parseObject(claims, OrderInfoVo.class);
        } catch (Exception e) {
            throw new GuiguException(201, "非法参数, 请重新下单");
        }
        //签名合法,包装DO的订单数据
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoVo, orderInfo);
        //覆盖支付方式
        orderInfo.setPayWay(payWay);
        //补全用户ID
        orderInfo.setUserId(AuthContextHolder.getUserId());
        //补全订单no
        orderInfo.setOrderNo(orderInfoVo.getTradeNo());
        //补全订单的描述
        orderInfo.setOrderTitle("VIP会员订单");
        //保存订单的数据
        if(orderInfoMapper.insert(orderInfo) <= 0){
            throw new GuiguException(201, "新增订单失败");
        }
        //获取订单id
        Long orderId = orderInfo.getId();
        //保存订单详情
        orderInfoVo.getOrderDetailVoList().stream().forEach(vo->{
            //初始化详情的DO
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(vo, orderDetail);
            //补全orderId
            orderDetail.setOrderId(orderId);
            //新增
            if(orderDetailMapper.insert(orderDetail) <= 0){
                throw new GuiguException(201, "新增订单失败!!!");
            }
        });
        //保存订单的减免详情
        List<OrderDerateVo> orderDerateVoList =
                orderInfoVo.getOrderDerateVoList();
        if(orderDerateVoList != null){
            orderDerateVoList.stream().forEach(vo->{
                //初始化减免的DO
                OrderDerate orderDerate = new OrderDerate();
                BeanUtils.copyProperties(vo, orderDerate);
                //补全orderId
                orderDerate.setOrderId(orderId);
                //新增
                if(orderDerateMapper.insert(orderDerate) <= 0){
                    throw new GuiguException(201, "新增订单失败!!!");
                }
            });
        }
        //返回结果初始化
        JSONObject result = new JSONObject();
        result.put("orderNo", orderInfo.getOrderNo());

        // 订单提交成功后 会被放入延迟队列 持续15分钟
        //入库时间点开始,订单支付倒计时:15分钟(10分钟): a.定时任务方案  b.延迟消息方案(最终方案)
        rabbitTemplate.convertAndSend(
                "tingshu_order_exchange",
                "tingshu.order",
                orderId + "",
                message -> {
                    //获取消息的属性
                    MessageProperties messageProperties = message.getMessageProperties();
                    //设置过期时间:毫秒
                    messageProperties.setExpiration("900000"); // 900秒(15分钟)
                    // messageProperties.setExpiration("20000"); // 20秒
                    //返回
                    return message;
                });
        //返回
        return result;
    }

    @Override
    public Object selectUserOrderPage(Integer page, Integer size) {
        return null;
    }

    @Override
    public OrderInfo getOrderInfo(String orderNo) {
        return null;
    }
}
